package ru.niir.goodfil;

import com.thoughtworks.xstream.XStream;
import org.apache.commons.cli.*;
import org.apache.commons.cli.ParseException;
import org.apache.commons.io.FileUtils;
import org.apache.commons.lang.StringUtils;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;
import org.apache.log4j.PropertyConfigurator;
import org.quartz.*;
import org.quartz.impl.StdSchedulerFactory;
import ru.niir.goodfil.c1.*;
import ru.niir.goodfil.c1.Client;
import ru.niir.goodfil.c1.Good;
import ru.niir.goodfil.c1.Order;
import ru.niir.goodfil.c1.OrderItem;
import ru.niir.goodfil.db.*;
import ru.niir.goodfil.db.dic.ExchangeState;
import ru.niir.goodfil.db.dic.OrderState;
import ru.niir.goodfil.db.handlers.Goodfil;
import ru.niir.goodfil.exceptions.MailerException;
import ru.niir.goodfil.exceptions.RemoveFailureException;
import ru.niir.goodfil.exceptions.ValidationException;
import ru.niir.goodfil.fun.ISSignature;
import ru.niir.goodfil.utils.ExportStringFormatter;
import ru.niir.goodfil.utils.Version;
import ru.niir.goodfil.utils.filters.GoodsFilter;

import javax.mail.MessagingException;
import java.io.*;
import java.nio.file.*;
import java.sql.Date;
import java.sql.Timestamp;
import java.text.*;
import java.util.*;
import java.util.Calendar;

import static ru.niir.goodfil.utils.Utils.*;

/*
    29.04.10
    - Сделал загрузку файлов в cp1251
    - Исправление бага с "исчезающим" файлом Ostatki.xml
 */

/**
 * Объект для взаимодействия с 1С. Принцип работы описан в документе "Протокол обмена информацией с 1C.doc"
 */
public class Goodwill1C implements Job{
    /**
     * Общая директория для обмена файлами с 1С
     */
    private static String directory;

    /**
     * Наименование каталога (внутри общей директории для обмена файлами с 1С), в который перемещаются файлы обмена с 1С
     * после обработки. (Файлы перемещаются и в случае успешной обработки, и в случае возникнования ошибок)
     */
    private static String proceedFilesCatalog;

    /**
     * Загружать файлы из 1С
     */
    private static boolean useIn = true;

    /**
     * Выгружать файлы в 1С
     */
    private static boolean useOut = true;

    /**
     * Объект для сериализации/десериализации XML файлов
     */
    private static XStream xs;

    /**
     * Объект для работы с БД
     */
    private static Goodfil gf;

    //
    //  section Протоколирование
    //
    static {
        gf = GoodfilFactory.getInstance();

        Properties props = new Properties();
        props.put("log4j.rootLogger", "error,file");
        props.put("log4j.logger.ru.niir.goodfil", "debug");
        props.put("log4j.appender.file", "org.apache.log4j.RollingFileAppender");
        props.put("log4j.appender.file.File", "/home/sazonov/logs/c1.log");
        props.put("log4j.appender.file.MaxFileSize", "1000KB");
        props.put("log4j.appender.file.MaxBackupIndex", "2");
        props.put("log4j.appender.file.layout", "org.apache.log4j.PatternLayout");
        props.put("log4j.appender.file.layout.ConversionPattern", "%d{dd.MM.yyyy HH:mm:ss,SSS} (%F:%L): %m%n");
        LogManager.resetConfiguration();
        PropertyConfigurator.configure(props);
    }

    private static final Logger logger = Logger.getLogger(Goodwill1C.class);

    /**
     * Вывести сообщение о фатальной ошибке без указания кода ошибки. В таком случае устанавливается код по-умолчанию -
     * 0
     *
     * @param msg сообщение об ошибке
     */
    private static void logFatal(String msg) {
        logFatal(msg, 0);
    }

    /**
     * Вывести сообщение о фатальной ошибке с указанием кода ошибки
     *
     * @param msg  сообщение об ошибке
     * @param code код ошибки
     */
    private static void logFatal(String msg, int code) {
        logger.fatal(msg);
        System.exit(code);
    }

    /**
     * Вывести сообщение о серьезной ошибке
     *
     * @param msg сообщение
     */
    private static void logError(String msg) {
        logger.error(msg);
    }

    /**
     * Вывести предупреждающее собщение
     *
     * @param msg сообщение
     */
    private static void logWarn(String msg) {
        logger.warn(msg);
    }

    /**
     * Вывести информационное сообщение
     *
     * @param msg сообщение
     */
    private static void logInfo(String msg) {
        logger.info(msg);
    }

    //  -----------------------------------------------------------------------------------------------

    /**
     * Инициализировать XStream
     */
    public static XStream getXStream() {
        if (xs == null) {
            xs = new XStream();
            xs.processAnnotations(Client.class);
            xs.processAnnotations(Document.class);
            xs.processAnnotations(Good.class);
            xs.processAnnotations(Order.class);
            xs.processAnnotations(OrderItem.class);
            xs.processAnnotations(Rest.class);
        }
        return xs;
    }

    private static void moveToProceed(File f) throws IOException {
        logInfo("Moving " + f.getName());

        if (f.getName().endsWith("Ostatki.xml")) {
            File oldOstatkiXml = new File(directory + File.separator + proceedFilesCatalog + File.separator + "Ostatki.xml");
            if (oldOstatkiXml.exists()) {
                oldOstatkiXml.delete();
            }
        }

        try {
            FileUtils.moveFile(f, new File(directory + File.separator + proceedFilesCatalog + File.separator + f.getName()));
        } catch (Exception e) {
            logError("Cannot move file (1): " + e);
            try {
                f.delete();
            } catch (Exception e2) {
                logError("Cannot move file (1): " + e2);
            }
        }
    }

    private static void proceedOutOrder(DataExchange dataExchange, Properties props, BooleanRef proceed) {
        if (!dataExchange.getTableName().equals("Orders")) {
            return;
        }

        //  Перед обработкой проверяем, что существует клиент и заказ, на который ссылается выгрузка
        //  Проверяем, что такой заказ существует
        long orderId = dataExchange.getItemId();
        ru.niir.goodfil.db.Order order = gf.getOrderById(orderId);
        if (order == null) {
            logError("Missing order " + orderId + ": skipped");
            proceed.set(false);
            return;
        }

        //  Проверяем, что такой клиент существует
        long clientId = order.getClientId();
        ru.niir.goodfil.db.Client client = gf.getClientById(clientId);
        if (client == null) {
            logError("Order #" + order.getId() + " was obtained with missing client (" + clientId + ")");
            return;
        }

        List<ru.niir.goodfil.db.OrderItem> orderItems = gf.getOrderItemsByOrderId(orderId);
        //  Загрузка соответствующих товаров для сортировки по коду
        for (ru.niir.goodfil.db.OrderItem orderItem : orderItems) {
            ru.niir.goodfil.db.Good g = gf.getGoodById(orderItem.getGoodId());
            orderItem.setGood(g);
        }

        //  Сортировка по коду товара
        Collections.sort(orderItems, new Comparator<ru.niir.goodfil.db.OrderItem>() {
            public int compare(ru.niir.goodfil.db.OrderItem orderItem1, ru.niir.goodfil.db.OrderItem orderItem2) {
                return orderItem1.getGood().getCode().compareTo(orderItem2.getGood().getCode());
            }
        });

        String comment = "???";
        try {
            ExportStringFormatter formatter = new ExportStringFormatter(order, orderItems);
            comment = formatter.formatExportString();
        } catch (Exception e) {
            comment = e.toString();
        }

        //  К этому моменту мы знаем, что с заказом все в порядке. Заполняем Properties
        if (props != null) {
            props.clear();

            SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm");
            String orderNum = String.valueOf(order.getId());
            String clientName = client.getCompanyName();
            String orderSum = String.valueOf(order.getSum());
            String orderCreationDate = sdf.format(order.getCreationDate());
            String dataExchangeId = String.valueOf(dataExchange.getId());
            String id1C = String.valueOf(order.getC1Num());
            String blockCheck = getBlockCheck(client.isBlockCheck());
         //   String priceColumn = "Колонка 1";

            props.setProperty("dataExchangeId", dataExchangeId);
            props.setProperty("managerId", String.valueOf(order.getManagerId()));
            props.setProperty("orderNum", orderNum);
            props.setProperty("clientName", clientName);
            props.setProperty("orderSum", orderSum);
            props.setProperty("orderCreationDate", orderCreationDate);
            props.setProperty("id1C", id1C);
            props.setProperty("blockCheck", blockCheck);
      //      props.setProperty("priceColumn", priceColumn);
        }

        Document document = Document.create(DocumentType.ORDERS);
        Order o = new Order(order.getId(),
                            order.getC1Num(),
                            client.getC1ClientNum(),
                            String.valueOf(client.getId()),
                            str(order.getCreationDate()),
                            comment,
                            String.valueOf(order.getFirm()),
                               gf.getClientGroupById(gf.getClientById(clientId).getClientgroupIdByBrandId(1)).getName(), getBlockCheck(client.isBlockCheck()));

        //  Если заказ неудаленный, добавляем его содержимое. Если удаленный - передаем пустую шапку.
        if (!order.isDeleted()) {


            for (ru.niir.goodfil.db.OrderItem orderItem : orderItems) {
                ru.niir.goodfil.db.Good good = gf.getGoodById(orderItem.getGoodId());
                int count;
                if(gf.getIsReservedOn()){
                    count = orderItem.getFactGivenFromStore();
                }
                else {
                    count = orderItem.getCount();
                }
                o.getItems().add(new OrderItem(good.getC1code(), count, orderItem.getItemPrice()));
            }
        }

        document.getOrders().add(o);

        if (writeDocument(document)) {
            gf.updateDataExchangeState(dataExchange.getId(), ExchangeState.SENT);
            proceed.set(true);
        }

        //  Надо не забыть удалить заказ вместе с закрытием выгрузки
    }

    private static void proceedOutOrderBuild(DataExchange dataExchange, Properties props, BooleanRef proceed) {
        if (!dataExchange.getTableName().equals("OrderBuild")) {
            return;
        }

        // Перед обработкой проверяем, что существует клиент и заказ, на который ссылается выгрузка
        //  Проверяем, что такой заказ существует
        long orderId = dataExchange.getItemId();
        ru.niir.goodfil.db.Order order = gf.getOrderById(orderId);
        if (order == null) {
            logError("Missing order " + orderId + ": skipped");
            proceed.set(false);
            return;
        }

        //  Проверяем, что такой клиент существует
        long clientId = order.getClientId();
        ru.niir.goodfil.db.Client client = gf.getClientById(clientId);
        if (client == null) {
            logError("Order #" + order.getId() + " was obtained with missing client (" + clientId + ")");
            proceed.set(false);
            return;
        }

        List<ru.niir.goodfil.db.OrderItem> orderItems = gf.getOrderItemsByOrderId(orderId);
        //  Загрузка соответствующих товаров для сортировки по коду
        for (ru.niir.goodfil.db.OrderItem orderItem : orderItems) {
            ru.niir.goodfil.db.Good g = gf.getGoodById(orderItem.getGoodId());
            orderItem.setGood(g);
        }

        //  Сортировка по коду товара
        Collections.sort(orderItems, new Comparator<ru.niir.goodfil.db.OrderItem>() {
            public int compare(ru.niir.goodfil.db.OrderItem orderItem1, ru.niir.goodfil.db.OrderItem orderItem2) {
                return orderItem1.getGood().getCode().compareTo(orderItem2.getGood().getCode());
            }
        });

        //  К этому моменту мы знаем, что с заказом все в порядке. Заполняем Properties
        if (props != null) {
            props.clear();

            SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm");
            String orderNum = String.valueOf(order.getId());
            String clientName = client.getCompanyName();
            String orderSum = String.valueOf(order.getSum());
            String orderCreationDate = sdf.format(order.getCreationDate());
            String dataExchangeId = String.valueOf(dataExchange.getId());

            props.setProperty("dataExchangeId", dataExchangeId);
            props.setProperty("managerId", String.valueOf(order.getManagerId()));
            props.setProperty("orderNum", orderNum);
            props.setProperty("clientName", clientName);
            props.setProperty("orderSum", orderSum);
            props.setProperty("orderCreationDate", orderCreationDate);
        }

        Document document = Document.create(DocumentType.ORDER_BUILD);
        Order o = new Order();
        o.setIdIS(order.getId());
        o.setId1C(order.getC1Num());
        o.setCreationDate(str(order.getCreationDate()));
       // o.setAddress(comment);

        for (ru.niir.goodfil.db.OrderItem orderItem : orderItems) {
            ru.niir.goodfil.db.Good good = gf.getGoodById(orderItem.getGoodId());
            o.getItems().add(new OrderItem(good.getC1code(), orderItem.getFactGivenFromStore(), orderItem.getItemPrice()));
        }
        document.getOrders().add(o);

        if (writeDocument(document)) {
            gf.updateDataExchangeState(dataExchange.getId(), ExchangeState.SENT);
            proceed.set(true);
        }
    }

    /*
    <Document type=”Clients”>
        <Clients>
            <Client
            idIS=”[значение идентификатора записи клиента из ИНТЕРНЕТ-системы]”
            id1C=”[значение идентификатора записи клиента из 1C]”
            name=”[наименование клиента для бухгалтерии]”
            managerFIO=”[фамилия курирующего менеджера]”/>
        </Clients>
    </Document>

     */
    private static void proceedOutClient(DataExchange dataExchange, BooleanRef proceed) {
        if (dataExchange.getTableName().equals("Clients")) {   //  Формирование документа для передачи данных о клиенте
            long clientId = dataExchange.getItemId();
            ru.niir.goodfil.db.Client client = gf.getClientById(clientId);

            if (client != null) {
                Document document = Document.create(DocumentType.ALL);

                Client c = new Client();
                c.setName(client.getCompanyName());
                c.setIdIS(client.getId());
                c.setPriceColumn(gf.getClientGroupById(client.getClientgroupIdByBrandId(1)).getName()); // Получение ценовой колонки
                if (!StringUtils.isEmpty(client.getC1ClientNum())) {
                    c.setId1C(client.getC1ClientNum());
                }

                User u = null;
                if (client.getManagerId() != null) {
                    u = gf.getUserById(client.getManagerId());
                }
                if (u != null) {
                    c.setManagerFIO(u.getFio());
                }
                document.getClients().add(c);

                if (writeDocument(document)) {
                    gf.updateDataExchangeState(dataExchange.getId(), ExchangeState.SENT);
                    proceed.set(true);
                }
            } else {
                logError("Missing client " + clientId + ": skipped!");
                gf.updateDataExchangeState(dataExchange.getId(), ExchangeState.SENT);
                proceed.set(false);
            }
        }
    }

    /**
     * Функция записывает в виде XML выходной документ. Решена проблема частичной записи: сначала все пишется во
     * временный файл (.tmp), а потом переименовывается.
     * <p/>
     * При этом проверяется: 1. Что в документе либо только один клиент, либо только один заказ (т.н. атомарная
     * выгрузка) 2. Для клиента - менеджер указан верно 3. Для заказа - верный клиент - верный товар 4. Для изменения
     * заказа НИЧЕГО НЕ ПРОВЕРЯЕТСЯ
     *
     * @param document
     * @return true, если выгрузка ушла в файл или false, если в выгрузке обнаружидись ошибки
     */
    private static boolean writeDocument(Document document) {
        try {
            if (!document.getType().equals(DocumentType.ORDER_BUILD)) {
                //  Проверяем, что выгрузка содержит либо одного клиента, либо один заказ
                if (document.getClients().size() == 1) {
                    logInfo("Writing document with client " + document.getClients().get(0).getIdIS());
                } else if (document.getOrders().size() == 1) {
                    logInfo("Writing document with order " + document.getOrders().get(0).getIdIS());
                }
                else if (document.getClients().size() == 0 && document.getOrders().size() == 0) {
                    logFatal("Out document has zero. It's a sin.");
                } else {
                    logFatal("Out document has more that one client or one order. It's a sin.");
                }

                //  Для каждого клиента в выгрузке проверяем, что он существует
                for (Client client : document.getClients()) {
                    ru.niir.goodfil.db.Client c = gf.getClientById(client.getIdIS());
                    if (c == null) {
                        logFatal("Missing client with id " + client.getIdIS() + " (writeDocument call, clients)");
                    }
                }

                //  Для каждого заказа в выгрузке проверяем, что он сущестует и существует клиент, на которого он оформлен
                for (Order order : document.getOrders()) {
                    //  Проверяем, что существует заказ
                    ru.niir.goodfil.db.Order o = gf.getOrderById(order.getIdIS());
                    if (o == null) {
                        logFatal("Missing order with id " + order.getIdClientIS() + " (writeDocument call, orders)");
                    }

                    //  Проверяем, что существует клиент
                    long clientId = Long.parseLong(order.getIdClientIS());
                    ru.niir.goodfil.db.Client c = gf.getClientById(clientId);
                    if (c == null) {
                        logFatal("Missing client with id " + clientId + " (writeDocument call, orders)");
                    }

                    //  Проверяем, что есть код соответствия для клиента
                    if (StringUtils.isBlank(order.getIdClient1c())) {
                        logFatal("Attemp to output order with bad idClient1C.");
                    }

                    //  Проверяем, что для каждой позиции заказа установлен код соответствия для товара
                    for (OrderItem item : order.getItems()) {
                        if (StringUtils.isBlank(item.getGoodCode1C())) {
                            logFatal("Attempt to output orderItem with bad goodCode1C.");
                        }
                    }
                }
            }

            //  Удаляем из документа пустые тэги
            document.trim();

            //  Записываем файл, не забывая закрывать дескриптор

            String filepath = directory + File.separator + generateFileName(ExchangeDirection.IS_TO_C1) + ".xml";
            String temppath = directory + File.separator + generateFileName(ExchangeDirection.IS_TO_C1) + ".temp";
            File tempFile = new File(temppath);
            OutputStream os = new FileOutputStream(tempFile);
            OutputStreamWriter osw = new OutputStreamWriter(os, "windows-1251");
            osw.write("<?xml version=\"1.0\" encoding=\"windows-1251\"?>\n");
            getXStream().toXML(document, osw);
            osw.close();
            os.close();
            tempFile.renameTo(new File(filepath));

            return true;
        } catch (IOException e) {
            logFatal("Cannot write document: " + e);
            e.printStackTrace();

            return false;
        }
    }

    /*
    <Document type=”Goods”>
        <Goods>
        <GoodCode1С=”[код товара в 1С]”
        GoodDefinition=”[строка описания товара]”/>
        …
        </Goods>
    </Document>
     */
    private static void proceedInputGoods(Document document) throws UnsupportedEncodingException {
        logInfo("Proceeding in goods section: " + document.getGoods().size() + " ..skipped");

//      Убрали обработку новых товаров из взаимодействия с 1С
//        if (document.getGoods().size() > 0)
//        {
//            Random r = new Random();
//            for (Good good : document.getGoods())
//            {
//                ru.niir.goodfil.db.Good g = new ru.niir.goodfil.db.Good();
//                g.setName(new String(good.getGoodDefinition().getBytes("windows-1251")));
//                g.setC1code(good.getGoodCode1C());
//                g.setCode(String.valueOf(Math.abs(r.nextInt())));
//                g.setGoodTypeId(1);
//                g.setMinPrice(1);
//                g.setPackageCount(1);
//                g.setWeight(1);
//                g.setVolume(1);
//                g.setCount(0);
//
//                try
//                {
//                    gf.saveGood(g);
//                }
//                catch (ValidationException e)
//                {
//                    logWarn("Cannot add new good: " + e.toString());
//                }
//                catch (CreateFailureException e)
//                {
//                    logWarn("Cannot add new good: " + e.toString());
//                }
//            }
//        }
    }

    /*
    <Document type=”Clients”>
        <Clients>
        <Client 	id1C=”[идентификатор записи клиента в 1C]”
                    idIS=”[идентификатор записи клиента в ИНТЕРНЕТ-системе]”
                    BankDebt=”[сумма долга по банку]”
                    CashDebt=”[ сумма долга по кассе]”/>
        </Clients>
    </Document>
     */
    private static void proceedInputClients(Document document) {
        logInfo("Proceeding in clients section: " + document.getClients().size());

        //  Получаем всех клиентов
        List<ru.niir.goodfil.db.Client> allClients = gf.getClients();

        //  Проверяем отсутствие задвоений
        try {
            Set<String> c1Set = new HashSet<String>();
            Set<Long> isSet = new HashSet<Long>();
            Set<Long> duplicatedIsSet = new HashSet<Long>();
            for (Client client : document.getClients()) {

                if (!StringUtils.isBlank(client.getId1C())) {
                    if (!c1Set.contains(client.getId1C())) {
                        c1Set.add(client.getId1C());
                    } else {
                        logError("Duplication of c1Code: " + client.getId1C());
                    }
                }

                if (client.getIdIS() > 0) {
                    if (!isSet.contains(client.getIdIS())) {
                        isSet.add(client.getIdIS());
                    } else {
                        duplicatedIsSet.add(client.getIdIS());
                    }
                }
            }

            for (Long isCode : duplicatedIsSet) {
                logError("Duplication of isCode " + isCode);
                for (Client client : document.getClients()) {
                    if (client.getIdIS() == isCode) {
                        logError("..c1Code: " + client.getId1C());
                    }
                }
            }

        } catch (Exception e) {
            logError(e.toString());
        }

        for (Client client : document.getClients()) {
            if (client.getIdIS() == 0) {
                continue;
            }

            try {
                ru.niir.goodfil.db.Client c = null;
                for (ru.niir.goodfil.db.Client cl : allClients) {
                    if (cl.getId() == client.getIdIS()) {
                        c = cl;
                    }
                }

                if (c == null) {
                    logError("While processing clients, we didn't find client with IdIS " + client.getIdIS());
                    continue;
                }
// Далее распарсить строку как буленовское значение сравнить его со значением текущей блокировки клиента
// И исходя из значения обновить блокировку клиенту.
                boolean hasChanged = false;
                boolean block = getc1Block(client.getC1Block());
                if(block^c.isC1Block()){
                    c.setC1Block(block);
                    hasChanged = true;
                }

                //  Назначаем чуваку код либо если его не было, либо если он изменился
                if (c.getC1CodeIsMissing() ||
                        (!c.getC1CodeIsMissing() && !c.getC1ClientNum().equals(client.getId1C()))) {
                    c.setC1ClientNum(client.getId1C());
                    hasChanged = true;
                    logInfo("Client " + c.getId() + ": c1Code set to " + client.getId1C());
                }

                //  Записываем долг по банку, только если он есть и изменился
                Float debtBank = number(client.getDebtBank());

                if (debtBank != null && c.getDebtBank() != debtBank) {
                    c.setDebtBank(debtBank);
                    hasChanged = true;
                    logInfo("Client " + c.getId() + ": debtBank set to " + debtBank);
                }

                //  Записываем долг по кассе, только если он есть и изменился
                Float debtCash = number(client.getDebtCash());
                if (debtCash != null && c.getDebtCash() != debtCash) {
                    c.setDebtCash(debtCash);
                    hasChanged = true;
                    logInfo("Client " + c.getId() + ": debtCash set to " + debtCash);
                }

                //  Обновляем клиента только если что-то изменилось
                if (hasChanged) {
                    c.setDeliveryInfoExt(null);
                    c.setVisibleBrands(null);
                    c.setVisibleClientGroups(null);
                    c.getClientgroups().clear();
                    gf.updateClient(c);
                    logInfo("Client " + c.getId() + " updated!");
                }
            } catch (ValidationException ve) {
                logWarn("Cannot update client: " + ve);
            } catch (NumberFormatException nfe) {
                logFatal("Cannot parse debtBank (" + client.getDebtBank() + ") or debtCash (" + client.getDebtCash() + ")");
            } catch (Exception e) {
                logWarn(e.toString());
                e.printStackTrace();
            }
        }
    }

    /*
    <Document type=”Rests”>
        <Rests>
        <Rest   goodCode1С=”[код товара в 1С]”
                freeCount=”[количество товара свободного для заказа]”
                reservedCount=”[количество товара в резерве]”/>
        …
        </Rests>
    </Document>
     */
    @Deprecated
    private static void proceedInputRests_old(Document document) {
        logInfo("Proceeding in rests section: " + document.getRests().size());

        for (Rest rest : document.getRests()) {
            String goodCode1C = rest.getGoodCode1C();
            List<ru.niir.goodfil.db.Good> goods = gf.getGoodsBy1CCode(goodCode1C);
            if (goods.size() > 1) {
                logWarn("More than one good with goodCode1C: " + goodCode1C);
                continue;
            }
            if (goods.size() == 0) {
                continue;
            }

            ru.niir.goodfil.db.Good good = goods.get(0);
            good.setCount(rest.getFreeCount());
            good.setReservedCount(rest.getReservedCount());

            try {
                gf.updateGood(good);
            } catch (Exception e) {
                e.printStackTrace();
                logFatal("Cannot update Good: " + e);
            }
        }
    }

    private static void proceedInputRests(Document document) {
        logInfo("Proceeding in rests section: " + document.getRests().size());

        GoodsFilter filter = new GoodsFilter();
        List<ru.niir.goodfil.db.Good> allGoods = gf.getGoods(0, Integer.MAX_VALUE, filter);

        for (Rest rest : document.getRests()) {
            String goodCode1C = rest.getGoodCode1C();
            List<ru.niir.goodfil.db.Good> goods = new ArrayList<ru.niir.goodfil.db.Good>();
            for (ru.niir.goodfil.db.Good good : allGoods) {
                if (!good.getC1CodeIsMissing() && good.getC1code().equals(goodCode1C)) {
                    goods.add(good);
                }
            }

            if (goods.size() > 1) {
                logWarn("More than one good with goodCode1C: " + goodCode1C);
                continue;
            }
            if (goods.size() == 0) {
                continue;
            }

            ru.niir.goodfil.db.Good good = goods.get(0);

            if (rest.getGoodCode1C().equals("00000267")) {
                int l = 5;
            }

            if(gf.getIsReservedOn()){
                int reservedCount = rest.getReservedCount();
                if(reservedCount < 0) reservedCount = 0;
                int c1count = rest.getFreeCount() - reservedCount;
                if(c1count < 0) c1count = 0;
                if (good.getCount() != c1count){
                    good.setCount(c1count);
                }
            }
            else {
                if (good.getCount() != rest.getFreeCount() ||
                        good.getReservedCount() != rest.getReservedCount()) {
                    good.setCount(rest.getFreeCount());
                    good.setReservedCount(rest.getReservedCount());
                }
            }
                try {
                    gf.updateGood(good);
                } catch (Exception e) {
                    e.printStackTrace();
                    logFatal("Cannot update Good: " + e);
            }
        }
    }

    /*
    <Document type=”Orders”>
        <Orders>
        <Order  id1C=”[значение идентификатора записи заказа из 1C]”
                idIS=”[значение идентификатора записи из заказа ИНТЕРНЕТ-системы]”/>
            <OrderItem  goodCode1C=”[код товара для 1С]”
                        count=”[количество товара]”/>
        …
        </Orders>
    </Document>
     */
    private static void proceedInputOrders(Document document) {
        logInfo("Proceeding in orders section: " + document.getOrders().size());

        for (Order order : document.getOrders()) {
            try {
                if (order.getItems().size() == 0) {   //  Заказ принят в 1С

                    ru.niir.goodfil.db.Order o = gf.getOrderById(order.getIdIS());
                    if (o == null) {
                        logWarn("No order with id " + order.getIdIS());
                        continue;
                    }

                    o.setC1Num(order.getId1C());
                    try {
                        gf.updateOrder(o);
                    } catch (ValidationException ve) {
                        logFatal("Cannot update order " + order.getIdIS() + ": " + ve);
                    }

                    if(!gf.getIsReservedOn()){
                        try {
                            gf.setOrderState_Unsafe(o.getId(), OrderState.ACCEPTED_BY_BUH);
                            gf.setOrderState_Unsafe(o.getId(), OrderState.OUTPUT);
                        } catch (Exception e) {
                            logFatal("Cannot change order status: " + e);
                        }
                    }
                }
            } catch (Exception e) {
                logFatal("Cannot proceed order " + order.getIdIS() + ": " + e);
            }
        }
    }

    private static void proceedInputOrderBuild(Document document) {
        if (document.getType().equals(DocumentType.ORDER_BUILD_RESPONSE)) {

            logInfo("Proceeding orderBuild response");
            String id1C = document.getResponse().getOrder().getId1C();
            String idIS = document.getResponse().getOrder().getIdIS();
            String result = document.getResponse().getOrder().getResult();

            if ("SUCCESS".equals(result)) {
            } else if ("ERROR_NO_ORDER".equals(result)) {
                write1COrderBuildError("ORDER_CHANGE_ERROR_NO_ORDER", idIS, id1C);
                logFatal("Cannot proccess orderBuild");
            } else if ("ERROR_RESTS".equals(result)) {
                write1COrderBuildError("ORDER_CHANGE_ERROR_RESTS", idIS, id1C);
                logFatal("Cannot proccess orderBuild");
            }
        }

    }


    private static void reportError(Exception e) throws Exception {
        try {
            StringWriter writer = new StringWriter();
            PrintWriter pw = new PrintWriter(writer);
            e.printStackTrace(pw);
            String stacktrace = writer.toString();

            Calendar c = Calendar.getInstance();
            String currentDate = new SimpleDateFormat("dd_MM_yyyy HH_mm").format(c.getTime());
            FileWriter fw = new FileWriter(currentDate + ".error");
            String text = "Внимание!\nВ работе модуля Интеграция с 1С был зафиксирован сбой.\nДата: " + sdf.format(c.getTime()) + "\n" + "Информация о сбое представлена ниже: \n" + " --- --- ---\n" + "" + stacktrace + " --- --- ---\n";
            fw.write(text);
            fw.close();

        } catch (Exception e2) {
            throw e;
        }
    }

    public static void main(String[] args) throws InterruptedException {
        while (true) {
            try {
                _main(args);
            } catch (Exception e) {
                try {
                    e.printStackTrace();
                    reportError(e);
                } catch (Exception e2) {
                    e.printStackTrace();
                    e2.printStackTrace();
                }
            }
            //  Пауза между перезапусками
            Thread.sleep(10000);
        }
    }

    /**
     * Запуск программы синхронизации с 1С. При запуске передается два параметра: -d должен указывать на каталог
     * содержащий файлы обмена данными с 1С -I загружать файлы -O выгружать файлы --proceed_files_catalog каталог с
     * обработанными файлами
     */
    public static void _main(String[] args) throws InterruptedException, SchedulerException, java.text.ParseException {
        Options options = new Options();
        options.addOption("d", "directory", true, "Shared directory");
        options.addOption("I", "In", false, "Use in");
        options.addOption("O", "Out", false, "Use out");
        options.addOption("new_goods_catalog", true, "Catalog for *.csv files with new/modified goods");
        options.addOption("proceed_files_catalog", true, "Catalog for proceed files");

        CommandLineParser parser = new PosixParser();
        try {
            CommandLine cmd = parser.parse(options, args);

            directory = cmd.getOptionValue("d");
            if (directory == null) {
                logFatal("Shared directory should be specified via argument -d");
            }

            useIn = cmd.hasOption("I");
            useOut = cmd.hasOption("O");

            proceedFilesCatalog = cmd.getOptionValue("proceed_files_catalog");
            if (proceedFilesCatalog == null) {
                logFatal("Catalog name for proceed files should be specieied via key `proceed_files_catalog`");
            }
        } catch (ParseException e) {
            logFatal("Cannot parse command line arguments");
        }

        logInfo("----------------------");
        logInfo("Goodwill 1C " + Version.getVersion() + " " + Version.getReleaseDate());
        logInfo("Directory             : " + directory);
        logInfo("Use IN                : " + useIn);
        logInfo("Use OUT               : " + useOut);
        logInfo("Proceed files catalog : " + proceedFilesCatalog);
        logInfo("----------------------");

        Scheduler scheduler = StdSchedulerFactory.getDefaultScheduler();
        scheduler.start();
        Trigger trigger = new CronTrigger("OstatkiTrigger",Scheduler.DEFAULT_GROUP,"0 0 0/1 * * ?");
        JobDetail jobDetail = new JobDetail("OstatkiParsed",Scheduler.DEFAULT_GROUP, Goodwill1C.class);
        Trigger blockTrigger = new CronTrigger("Block recovery", Scheduler.DEFAULT_GROUP, "0 30 23 * * ?");
        JobDetail jobDetailBlock = new JobDetail("Block Recovery", Scheduler.DEFAULT_GROUP, BlockTrigger.class);
        scheduler.scheduleJob(jobDetail,trigger);
        scheduler.scheduleJob(jobDetailBlock, blockTrigger);

        while (true) {
            Thread.sleep(100);

            File dir = new File(directory);
            if (!dir.exists()) {
                logFatal("Shared directory doesn't exist");
            }
            if (!dir.isDirectory()) {
                logFatal("Shared directory is not a directory");
            }
            if (!useIn && !useOut) {
                logFatal("useIn is false and useOut is false, so there's nothing to do. Goodbye!");
            }

            /*
                Алгоритм должен быть таков:

                1. Загрузили от 1С выгрузки "Остатки" и "Долги", если такие присутствуют
                1. Сделали одну выгрузку
                3. Проверили, ушла ли наша выгрузка и появилось ли сообщениеоб ошибке
                4.1. Если наша выгрузка ушла: ждем пока появится выгрузка от 1С "Клиент" или "Заказ".
                     Дождавшись:
                        - загружаем выгрузку(и)
                        - добавляем в Журнал сообщение об успешной загрузке
                        - закрываем загрузку в БД
                        - к началу цикла

                4.2. Если наша выгрузка не ушла и сообщение об ошибке не появилось:
                        - письмо Администратору о том, что 1С не запущен
                        - ждать выхода из цикла 3-4.2

                 4.3. Если наша выгрузка не ушла и сообщение об ошибке появилось:
                        - письмо Администратору об ошибке
                        - добавить в Журнал сообщение об ошибке
                        - удалить ошибочную выгрузку
                        - не закрывать выгрузку в БД
                        - выход
            */

            File errorFile = new File(directory + File.separator + "errors" + File.separator + "last_error.txt");
            File clientIsBlockedErrorFile = new File(directory + File.separator + "errors" + File.separator + "Error_Client_is_block.txt");
            File goodEnoughErrorFile = new File(directory + File.separator + "errors" + File.separator + "ERROR_ORDER_BAD_RESTS.txt");
            proceed1CError(errorFile);

            /*
                Разбираем файл Ostatki.xml

                В нем могут быть:
                 - остатки
                 - долги
                 - реализации
                 - товары
             */
            // proceedOstatki(dir);

/*            for (File f : dir.listFiles()) {
                if (!f.getName().endsWith("Ostatki.xml")) {
                    continue;
                }

                try {
                    FileInputStream fis = new FileInputStream(f);
                    InputStreamReader in = new InputStreamReader(fis, "windows-1251");
                    Document document = null;
                    try {
                        document = (Document) getXStream().fromXML(in);
                    } catch (Exception e) {
                    }

                    if (document == null) {
                        //  EXPERIMENTAL: Может приходить битый файл с остатками, к этому нужно спокойно относиться
                        logError("Cannot parse Ostatki.xml from 1C");
                        Thread.sleep(300);
                        continue;
//                        throw new RuntimeException("Cannot parse file from 1C ");
                    }

                    in.close();
                    fis.close();

                    if ((document.getRests() == null || document.getRests().size() == 0) &&
                            (document.getGoods() == null || document.getGoods().size() == 0) &&
                            (document.getClients() == null || document.getClients().size() == 0) &&
                            (document.getOrders() == null || document.getOrders().size() == 0) &&
                            document.getResponse() == null) {
                        continue;
                    }
                    proceedInputRests(document);        //  Остатки
                    proceedInputGoods(document);        //  Товары
                    proceedInputClients(document);      //  Долги
                    proceedInputOrders(document);       //  Реализации
                    proceedInputOrderBuild(document);

                    SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
                    java.util.Date current = Calendar.getInstance().getTime();
                    gf.createIfNotExists(".1c.rests.last", sdf.format(current), "Дата последней загрузки остатков");
                    gf.set(".1c.rests.last", sdf.format(current));

                    //  Перемещаем в папку proceed файл Ostatki.xml
                    moveToProceed(f);
                } catch (IOException ioe) {   //  Если не можем прочесть - НЕ выход (EXPERIMENTAL)
                    ioe.printStackTrace();
                    logError("Cannot read file: " + f.getName() + ". Exception: " + ioe);
                }
            }*/

            proceed1CError(errorFile);

            //  Тут на всякий случай разбираем входящие файлы от 1С
            for (File file : dir.listFiles(from1CtoISfilter)) {
                // Very strange
                if (file.isDirectory()) {
                    continue;
                }
                if (!file.getName().endsWith(".xml")) {
                    continue;
                }

                try {
                    FileInputStream fis = new FileInputStream(file);
                    InputStreamReader in = new InputStreamReader(fis, "windows-1251");
                    Document document = (Document) getXStream().fromXML(in);
                    in.close();
                    fis.close();

                    logInfo("Proceeding UNEXPECTED file");
                    proceedInputClients(document);
                    proceedInputGoods(document);
                    proceedInputOrders(document);
                    proceedInputOrderBuild(document);

                    //  Перемещаем в папку proceed файл from1CtoIS.xml
                    moveToProceed(file);
                } catch (IOException ioe) {
                    ioe.printStackTrace();
                    logFatal("Cannot read file: " + file.getName() + ". Exception: " + ioe);
                }
            }

            proceed1CError(errorFile);

            //  Теперь делаем одну выгрузку и не закрываем ее пока
            Properties props = new Properties();
            String lastFromISto1C = null;
            DataExchange dataExchange = gf.getNextDataExchange();
            if (dataExchange == null) {
                continue;
            }

            if (dataExchange.getTableName().equals("Clients")) {
                BooleanRef proceed = new BooleanRef(false);
                proceedOutClient(dataExchange, proceed);

                if (!proceed.get()) {
                    continue;
                }
                lastFromISto1C = "Client";
            }
            if (dataExchange.getTableName().equals("Orders")) {
                BooleanRef proceed = new BooleanRef(false);
                proceedOutOrder(dataExchange, props, proceed);

                if (!proceed.get()) {
                    continue;
                }
                lastFromISto1C = "Order";
            }

            if(dataExchange.getTableName().equals(DocumentType.ORDER_PRINT)){
                BooleanRef proceed = new BooleanRef(false);
                proceedOutOrderPrint(dataExchange, props, proceed);
                if(!proceed.get()){
                    continue;
                }
                lastFromISto1C = "OrderPrint";
            }

            if (dataExchange.getTableName().equals("OrderBuild")) {
                BooleanRef proceed = new BooleanRef(false);
                proceedOutOrderBuild(dataExchange, props, proceed);

                if (!proceed.get()) {
                    continue;
                }
                lastFromISto1C = "OrderBuild";
            }

            if(dataExchange.getTableName().equals("Rests")){
                BooleanRef proceed = new BooleanRef(false);
                String key = "can.storage.confirm.orders";
                // Время начала выгрузки
                Calendar startTime = Calendar.getInstance();
                System.out.println(startTime.getTime() + " Rest upload start. Storage can't commit orders");
                // Остановить выполнение текущего потока на 5-6 мин. Это нужно для того, чтобы файл с остатками и блокировками перезаписался два раза
                // и в нем точно зафиксировались последние изменения.
                try {
                    System.out.println("Delay");
                    String value = "0";
                    gf.set(key,value);
                    Thread.sleep(300000);

                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
                System.out.println("File search start");
                // Флаг, указывающий, что файл с остатками найден
                boolean isOstatkiEsist = false;
                // Пока файл не найден делаем цикл
                while (!isOstatkiEsist){
                    // Проверка каждого файла в дирректории
                    for (File f : dir.listFiles()) {
                        if (!f.getName().endsWith("Ostatki.xml")) {
                            continue;
                        }
                        // Если файл найден - запускаем выгрузку остатков
                        System.out.println("File is exist");
                        proceedOstatki(dataExchange, f, proceed);
                        // выходим из цикла
                        isOstatkiEsist = true;
                    }
                }
                // Это на всякий случай. В этом блоке на самом деле не нужно
                if(!proceed.get()){
                    continue;
                }
                // Если ошибок не найдено, то закрываем выгрузку и запускаем главный цикл заново
                gf.closeDataExchange(dataExchange.getId());
                String value = "1";
                gf.set(key, value);
                continue;
            }

            proceed1CError(errorFile);

            //  Начиная отсюда можно мониторить ошибку Error_Client_is_blocked
            try {
                proceedClientBlockedError(clientIsBlockedErrorFile, props);
                proceedNotEnoughGoodError(goodEnoughErrorFile, props);
                boolean clientIsBlocked = false;
                //  Ждем ответа
                logInfo("Waiting... (stage 1)");
                while (true) {

                    //  EXPERIMENTAL
                    //  Странное поведение: ошибка записалась, но файлик не ушел.
                    //  Так должно быть или нет?
                    //
                    proceed1CError(errorFile);
                    proceedClientBlockedError(clientIsBlockedErrorFile, props);
                    proceedNotEnoughGoodError(goodEnoughErrorFile, props);
                    if (dir.listFiles(fromISto1Cfilter).length == 0) {   //  Файл ушел. Закрываем выгрузку и ждем ответа.

                        logInfo("1C received file. Waiting for response (stage 2)");
                        proceed1CError(errorFile);

                        proceedClientBlockedError(clientIsBlockedErrorFile, props);
                        proceedNotEnoughGoodError(goodEnoughErrorFile, props);

                        while (true) {
                            proceed1CError(errorFile);

                            proceedClientBlockedError(clientIsBlockedErrorFile, props);
                            proceedNotEnoughGoodError(goodEnoughErrorFile, props);
                            boolean found = false;
                            for (File file : dir.listFiles(from1CtoISfilter)) {
                                // Very strange
                                if (file.isDirectory()) {
                                    continue;
                                }
                                if (!file.getName().endsWith(".xml")) {
                                    continue;
                                }

                                try {
                                    FileInputStream fis = new FileInputStream(file);
                                    InputStreamReader in = new InputStreamReader(fis, "windows-1251");
                                    Document document = (Document) getXStream().fromXML(in);
                                    in.close();
                                    fis.close();

                                    if ((DocumentType.ALL.equals(document.getType()) ||
                                            DocumentType.ORDERS.equals(document.getType())) &&
                                            document.getOrders().size() > 0) {   //  Ответ на заказ
                                        if (document.getClients().size() != 0) {
                                            logWarn("Orders document also has clients");
                                            proceedInputClients(document);
                                        }
                                        if (document.getGoods().size() != 0) {
                                            logWarn("Orders document also has goods");
                                            proceedInputGoods(document);
                                        }
                                        if (document.getRests().size() != 0) {
                                            logWarn("Orders document also has rests");
                                            proceedInputRests(document);
                                        }
                                        if (lastFromISto1C == null) {
                                            logFatal("It's very strange: we receieved an order from 1C, but we've sent nothing");
                                        }

                                        logInfo("Proceeding orders response");
                                        assert lastFromISto1C != null;

                                        if(lastFromISto1C.equals("Order")){
                                            proceedInputOrders(document);
                                        }
                                        else if(lastFromISto1C.equals(DocumentType.ORDER_PRINT)){
                                            try {
                                                sendCalculationToManager(dataExchange, document);
                                            } catch (MessagingException e) {
                                                logError(e.getMessage());
                                            }
                                        }
                                        //  section Удаление заказа
                                        Order toDelete = document.getOrders().get(0);
                                        ru.niir.goodfil.db.Order _toDelete = gf.getOrderById(toDelete.getIdIS());
                                        if (_toDelete != null && _toDelete.isDeleted()) {
                                            logInfo("Removing order: " + toDelete.getIdIS());
                                            try {
                                                gf.removeOrder(_toDelete.getId());
                                            } catch (RemoveFailureException e) {
                                                e.printStackTrace();
                                                logError("Cannot remove order: " + e);
                                            }
                                        }

                                        //  Перемещаем в папку proceed файл from1CtoIS.xml
                                        moveToProceed(file);
                                        found = true;
                                        logInfo("Closing data exchange");
                                        gf.closeDataExchange(dataExchange.getId());

                                        break;
                                    }
                                    if ((DocumentType.ALL.equals(document.getType()) ||
                                            DocumentType.CLIENTS.equals(document.getType())) &&
                                            document.getClients().size() > 0) {   //  Ответ на клиента
                                        if (document.getOrders().size() != 0) {
                                            logWarn("Clients document also has orders");
                                            proceedInputOrders(document);
                                        }
                                        if (document.getGoods().size() != 0) {
                                            logWarn("Clients document also has goods");
                                            proceedInputGoods(document);
                                        }
                                        if (document.getRests().size() != 0) {
                                            logWarn("Clients document also has rests");
                                            proceedInputRests(document);
                                        }

                                        if (lastFromISto1C == null) {
                                            logFatal("It's very strange: we receieved a client from 1C, but we've sent nothing");
                                        }

                                        logInfo("Proceeding clients response");
                                        proceedInputClients(document);
                                        //  Перемещаем в папку proceed файл from1CtoIS.xml
                                        moveToProceed(file);
                                        found = true;
                                        logInfo("Closing data exchange");
                                        gf.closeDataExchange(dataExchange.getId());
                                        break;
                                    }

                                    if (document.getType().equals(DocumentType.ORDER_BUILD_RESPONSE)) {

                                        logInfo("Proceeding orderBuild response");
                                        proceedInputOrderBuild(document);
                                        found = true;
                                        moveToProceed(file);
                                        logInfo("Closing data exchange");
                                        gf.closeDataExchange(dataExchange.getId());
                                        break;
                                    }

                                } catch (IOException ioe) {
                                    ioe.printStackTrace();
                                    logFatal("Cannot read file: " + file.getName() + ". Exception: " + ioe);
                                }
                            }

                            if (found) {
                                break;
                            }
                            Thread.sleep(100);
                        }

                        break;
                    }


                    Thread.sleep(100);
                }
            } catch (ClientIsBlockedException e) {
                logInfo("CLIENT IS BLOCKED -> CONTINUE");
            }
        }
    }

    /**
     * Генерация файла с ошибкой от 1С. Это необходимо в случаях, когда 1С уведомляет ИС об ошибке в с помощью файла
     * last_error, а в xml файле from1CtoIS. В таком случае мы генерим файл last_error самостоятельно, как будто бы его
     * прислала 1С, так как ИС расчитывает считать ошибку из этого файла.
     *
     * @param errorName наименование ошибки (это либо ORDER_CHANGE_ERROR_NO_ORDER либо ORDER_CHANGE_ERROR_RESTS)
     * @param id1C      номер заказа в 1С
     * @param idIS      номер заказа в ИС
     */
    private static void write1COrderBuildError(String errorName, String idIS, String id1C) {
        _assertNotBlank(errorName);
        _assertNotBlank(idIS);
        _assertNotBlank(id1C);

        logInfo("Generating 1C error file");

        File errorFile = new File(directory + File.separator + "errors" + File.separator + "last_error.txt");
        FileWriter fw = null;
        try {
            fw = new FileWriter(errorFile);
            fw.write(errorName + "\n");
            fw.write("id1C=" + id1C + "\n");
            fw.write("idIS=" + idIS + "\n");
        } catch (IOException ioe) {
            logError(ioe.toString());
            logError("Cannot write 1C error file");
        }

        Properties props = new Properties();
        try {
            props.store(new FileWriter(errorFile), "");
        } catch (IOException ioe) {

        }
    }

    private static void proceed1CError(File errorFile) {
        if (errorFile.exists()) {   //  Загрузить сообщение об ошибке, отправить письмо администратору и приостановить обмен
            logInfo("1C error found");

            //  Загрузить ошибку в БД
            Properties props = new Properties();
            try {
                props.load(new InputStreamReader(new FileInputStream(errorFile), "windows-1251"));
                logWarn(props.toString());
            } catch (IOException ioe) {
                logError(ioe.toString());
                logError("Cannot read/parse 1C error file");
            }

            //  Направить администратору системы письмо с уведомлением об ошибке 1С
            try {
                String adminMail = gf.get("admin.mail");
                String header = "Обмен с 1С приостановлен";
                String text = "Уважаемый Администратор ИС!\n" +
                        "\n" +
                        "Только что обмен с 1С был приостановлен. Это штатная ситуация, но она требует вмешательства Администратора ИС.\n" +
                        "Обычно требуется удалить заказ из таблицы обмена, далее перевести в статус \"Предварительно сохранен\", после чего провести повторно.\n" +
                        "Ниже приведена информация из файла с ошибкой. Возможно, она поможет Вам с определением проблемы.\n" +
                        "\n" +
                        props.toString() +
                        "\n\n" +
                        ISSignature.get();
                gf.sendEmailMsg(adminMail, header, text);
            } catch (MailerException e) {
                logError("Cannot send email to administrator: " + e);
            }

            //  Выходим
            logFatal("Exit: 1C error found");
        }
    }

    /**
     * Обработка файла Error_Client_is_blocked
     *
     * @param errorFile файл с ошибкой
     * @param orderInfo
     * @return true, если ошибка была обработана, false, если ошибки не было
     */
    private static void proceedClientBlockedError(File errorFile, Properties orderInfo) throws ClientIsBlockedException {
        if (errorFile.exists()) {
            logInfo("ERROR CLIENT IS BLOCKED FOUND");

            long managerId = new Long(orderInfo.getProperty("managerId"));
            logInfo("managerId: " + managerId);

            //  Закрыть выгрзку
            long dataExchangeId = new Long(orderInfo.getProperty("dataExchangeId"));
            logInfo("dataExchangeId: " + dataExchangeId);
            gf.closeDataExchange(dataExchangeId);
            logInfo("..closed");

            //  Перевести заказ в статус "На согласовании"
            long orderId = new Long(orderInfo.getProperty("orderNum"));
            logInfo("orderId: " + orderId);
            gf.setOrderState_Unsafe(orderId, OrderState.PRE_SAVED);
            logInfo("..presaved");

            //  Отправить письмо менеджеру

            //  22.05.11 Если менеджер замещается, то нужно отправить письмо замещающему
            String adminMail = gf.get("admin.mail");
            User manager = gf.getUserById(managerId);
            _assertNotNull(manager);

            List<Replacement> replacements = gf.getActiveReplacementsByManagerId(managerId);
            _assertNotNull(replacements);
            _assert(replacements.size() == 0 || replacements.size() == 1);

            if (replacements.size() == 1) {
                Replacement replacement = replacements.get(0);
                logInfo("Manager " + replacement.getManagerId() + " replaced by " + replacement.getAssistantId());
                manager = gf.getUserById(replacement.getAssistantId());
                _assertNotNull(manager);
            }

            logInfo("Emailing: " + manager.getEmail());
            if (manager != null) {
                String email = manager.getEmail();
                String fio = manager.getFio();

                String orderNum = "<не указано>";   //  Номер заказа
                String clientName = "<не указано>";   //  Наименование клиента
                String orderSum = "<не указано>";   //  Сумма
                String orderCreationDate = "<не указано>";   //  Дата создания
                if (orderInfo != null) {
                    if (orderInfo.containsKey("orderNum")) {
                        orderNum = orderInfo.getProperty("orderNum");
                    }
                    if (orderInfo.containsKey("clientName")) {
                        clientName = orderInfo.getProperty("clientName");
                    }
                    if (orderInfo.containsKey("orderSum")) {
                        orderSum = orderInfo.getProperty("orderSum");
                    }
                    if (orderInfo.containsKey("orderCreationDate")) {
                        orderCreationDate = orderInfo.getProperty("orderCreationDate");
                    }
                }

                if (!StringUtils.isBlank(email) && email.contains("@")) {
                    String text = "Уважаемый(-ая) " + fio + "!\n" +
                            "Данное письмо было сгенерировано автоматически ИНТЕРНЕТ-системой в связи с тем, что Ваш \n" +
                            "заказ номер " + orderNum + " на сумму " + orderSum + " от " + orderCreationDate + " оформленный \n" +
                            "на клиента " + clientName + " не может быть проведен в 1С, так как данный клиент ЗАБЛОКИРОВАН.\n\n" +
                            "Данный заказ был автоматически переведен в статус \"Предварительно сохранен\".\n\n" +
                            "С Уважением, \nАдминистрация ИНТЕРНЕТ-системы.";

                    try {
                        gf.sendEmailMsg(email, text);
                        logInfo("..emailed");
                    } catch (MailerException e) {
                        logError("Cannot send email to manager, because of blocked client");
                    }
                }
            }

            //  Отправить письмо администратору
            if (!StringUtils.isBlank(adminMail)) {
                String orderNum = "<не указано>";   //  Номер заказа
                String clientName = "<не указано>";   //  Наименование клиента
                String orderSum = "<не указано>";   //  Сумма
                String orderCreationDate = "<не указано>";   //  Дата создания
                if (orderInfo != null) {
                    if (orderInfo.containsKey("orderNum")) {
                        orderNum = orderInfo.getProperty("orderNum");
                    }
                    if (orderInfo.containsKey("clientName")) {
                        clientName = orderInfo.getProperty("clientName");
                    }
                    if (orderInfo.containsKey("orderSum")) {
                        orderSum = orderInfo.getProperty("orderSum");
                    }
                    if (orderInfo.containsKey("orderCreationDate")) {
                        orderCreationDate = orderInfo.getProperty("orderCreationDate");
                    }
                }

                if (!StringUtils.isBlank(adminMail) && adminMail.contains("@")) {
                    String text = "Уважаемый Администратор!\n" +
                            "Данное письмо было сгенерировано автоматически ИНТЕРНЕТ-системой в связи с тем, что Ваш \n" +
                            "заказ номер " + orderNum + " от " + orderCreationDate + " оформленный \n" +
                            "на клиента " + clientName + " не может быть проведен в 1С, так как данный клиент ЗАБЛОКИРОВАН.\n\n" +
                            "Данный заказ был автоматически переведен в статус \"Предварительно сохранен\".\n\n" +
                            "С Уважением, \nАдминистрация ИНТЕРНЕТ-системы." +
                            "\n------------------------------------------------\n" +
                            "Administrator!\n" +
                            "This letter was generated automatically by INTERNET-system, cause of the fact, that your\n" +
                            "order number " + orderNum + " created " + orderCreationDate + " for\n" +
                            "client" + clientName + " cannot be processed via 1C, cause current client IS BLOCKED.\n\n" +
                            "Administration of INTERNET-system.\n";

                    try {
                        gf.sendEmailMsg(adminMail, text);
                        logInfo("..emailed");
                    }
//                    catch (UnsupportedEncodingException e)
//                    {
//                        logError("Cannot send email to administrator, because of blocked client");
//                    }
                    catch (MailerException e) {
                        logError("Cannot send email to administrator, because of blocked client");
                    }
                }
            }

            //  Удалить файл
            logInfo("Deleting...");
            errorFile.delete();
            logInfo("..deleted");

            throw new ClientIsBlockedException(managerId, dataExchangeId, orderId);
        }
    }


    /**
     * Обработка файла Error_Good_enough. Для предотвращения падений 1С при недостатке товара.
     *
     * @param errorFile файл с ошибкой
     * @param orderInfo
     *
     */
    private static void proceedNotEnoughGoodError(File errorFile, Properties orderInfo) throws ClientIsBlockedException {
        if (errorFile.exists()) {
            logInfo("ERROR BAD GOOD REST FOUND");

            long managerId = new Long(orderInfo.getProperty("managerId"));
            logInfo("managerId: " + managerId);

            //  Закрыть выгрзку
            long dataExchangeId = new Long(orderInfo.getProperty("dataExchangeId"));
            logInfo("dataExchangeId: " + dataExchangeId);
            gf.closeDataExchange(dataExchangeId);
            logInfo("..closed");

            //  Перевести заказ в статус "На согласовании"
            long orderId = new Long(orderInfo.getProperty("orderNum"));
            logInfo("orderId: " + orderId);
            gf.setOrderState_Unsafe(orderId, OrderState.PRE_SAVED);
            logInfo("..presaved");

            //  Отправить письмо менеджеру

            //  22.05.11 Если менеджер замещается, то нужно отправить письмо замещающему
            String adminMail = gf.get("admin.mail");
            User manager = gf.getUserById(managerId);
            _assertNotNull(manager);

            List<Replacement> replacements = gf.getActiveReplacementsByManagerId(managerId);
            _assertNotNull(replacements);
            _assert(replacements.size() == 0 || replacements.size() == 1);

            if (replacements.size() == 1) {
                Replacement replacement = replacements.get(0);
                logInfo("Manager " + replacement.getManagerId() + " replaced by " + replacement.getAssistantId());
                manager = gf.getUserById(replacement.getAssistantId());
                _assertNotNull(manager);
            }

            logInfo("Emailing: " + manager.getEmail());
            if (manager != null) {
                String email = manager.getEmail();
                String fio = manager.getFio();

                String orderNum = "<не указано>";   //  Номер заказа
                String clientName = "<не указано>";   //  Наименование клиента
                String orderSum = "<не указано>";   //  Сумма
                String orderCreationDate = "<не указано>";   //  Дата создания
                if (orderInfo != null) {
                    if (orderInfo.containsKey("orderNum")) {
                        orderNum = orderInfo.getProperty("orderNum");
                    }
                    if (orderInfo.containsKey("clientName")) {
                        clientName = orderInfo.getProperty("clientName");
                    }
                    if (orderInfo.containsKey("orderSum")) {
                        orderSum = orderInfo.getProperty("orderSum");
                    }
                    if (orderInfo.containsKey("orderCreationDate")) {
                        orderCreationDate = orderInfo.getProperty("orderCreationDate");
                    }
                }

                if (!StringUtils.isBlank(email) && email.contains("@")) {
                    String text = "Уважаемый(-ая) " + fio + "!\n" +
                            "Данное письмо было сгенерировано автоматически ИНТЕРНЕТ-системой в связи с тем, что Ваш \n" +
                            "заказ номер " + orderNum + " на сумму " + orderSum + " от " + orderCreationDate + " оформленный \n" +
                            "на клиента " + clientName + " не может быть проведен в 1С, так как на складе НЕДОСТАТОЧНО ТОВАРА.\n\n" +
                            "Данный заказ был автоматически переведен в статус \"Предварительно сохранен\".\n\n" +
                            "С Уважением, \nАдминистрация ИНТЕРНЕТ-системы.";

                    try {
                        gf.sendEmailMsg(email, text);
                        logInfo("..emailed");
                    } catch (MailerException e) {
                        logError("Cannot send email to manager, because of blocked client");
                    }
                }
            }

            //  Отправить письмо администратору
            if (!StringUtils.isBlank(adminMail)) {
                String orderNum = "<не указано>";   //  Номер заказа
                String clientName = "<не указано>";   //  Наименование клиента
                String orderSum = "<не указано>";   //  Сумма
                String orderCreationDate = "<не указано>";   //  Дата создания
                if (orderInfo != null) {
                    if (orderInfo.containsKey("orderNum")) {
                        orderNum = orderInfo.getProperty("orderNum");
                    }
                    if (orderInfo.containsKey("clientName")) {
                        clientName = orderInfo.getProperty("clientName");
                    }
                    if (orderInfo.containsKey("orderSum")) {
                        orderSum = orderInfo.getProperty("orderSum");
                    }
                    if (orderInfo.containsKey("orderCreationDate")) {
                        orderCreationDate = orderInfo.getProperty("orderCreationDate");
                    }
                }

                if (!StringUtils.isBlank(adminMail) && adminMail.contains("@")) {
                    String text = "Уважаемый Администратор!\n" +
                            "Данное письмо было сгенерировано автоматически ИНТЕРНЕТ-системой в связи с тем, что Ваш \n" +
                            "заказ номер " + orderNum + " от " + orderCreationDate + " оформленный \n" +
                            "на клиента " + clientName + " не может быть проведен в 1С, так как на складе НЕДОСТАТОЧНО ТОВАРА.\n\n" +
                            "Данный заказ был автоматически переведен в статус \"Предварительно сохранен\".\n\n" +
                            "С Уважением, \nАдминистрация ИНТЕРНЕТ-системы." +
                            "\n------------------------------------------------\n" +
                            "Administrator!\n" +
                            "This letter was generated automatically by INTERNET-system, cause of the fact, that your\n" +
                            "order number " + orderNum + " created " + orderCreationDate + " for\n" +
                            "client" + clientName + " cannot be processed via 1C, cause good has enough.\n\n" +
                            "Administration of INTERNET-system.\n";

                    try {
                        gf.sendEmailMsg(adminMail, text);
                        logInfo("..emailed");
                    }
//                    catch (UnsupportedEncodingException e)
//                    {
//                        logError("Cannot send email to administrator, because of blocked client");
//                    }
                    catch (MailerException e) {
                        logError("Cannot send email to administrator, because of blocked client");
                    }
                }
            }

            //  Удалить файл
            logInfo("Deleting...");
            errorFile.delete();
            logInfo("..deleted");

            throw new ClientIsBlockedException(managerId, dataExchangeId, orderId);
        }
    }

    /**
     * Фильтр для выборки файлов от 1С в ИС. Это может быть либо ответ на заказ, либо ответ на клиента.
     */
    private static FilenameFilter from1CtoISfilter = new FilenameFilter() {
        public boolean accept(File dir, String name) {
            int dotPosition = name.indexOf(".");
            int linePosistion = name.indexOf("_");
            int dotPositionLast = name.lastIndexOf(".");
            int linePosistionLast = name.lastIndexOf("_");


            return name.startsWith("from1CtoIS") &&
                    name.endsWith(".xml") &&
                    linePosistion == linePosistionLast &&
                    dotPosition == dotPositionLast;
        }
    };

    /**
     * Фильтр для выборки файлов от ИС в 1С. Это может быть либо выгрузка заказа либо выгрузка клиента.
     */
    private static FilenameFilter fromISto1Cfilter = new FilenameFilter() {
        public boolean accept(File dir, String name) {
            int dotPosition = name.indexOf(".");
            int linePosistion = name.indexOf("_");
            int dotPositionLast = name.lastIndexOf(".");
            int linePosistionLast = name.lastIndexOf("_");

            //  В имени есть одно подчеркивание, одна точка, имя начинается на fromISto1C и оканчивается на .xml
            return name.startsWith("fromISto1C") &&
                    name.endsWith(".xml") &&
                    linePosistion == linePosistionLast &&
                    dotPosition == dotPositionLast;
        }
    };

    private static SimpleDateFormat sdf = new SimpleDateFormat("yyyyMMddHHmmss");

    public static String generateFileName(String exchangeDirection) {
        _assertNotNull(exchangeDirection);
        _assert(exchangeDirection.equals(ExchangeDirection.C1_TO_IS) || exchangeDirection.equals(ExchangeDirection.IS_TO_C1));

        return exchangeDirection + "_" + sdf.format(Calendar.getInstance().getTime());
    }

    /**
     * Привести строку к floatу, даже если там int =)
     *
     * @param s строка
     * @return float
     */
    public static Float number(String s) {
        if (StringUtils.isBlank(s)) {
            return null;
        }

        Float result = null;
        try {
            result = Float.parseFloat(s);
        } catch (NumberFormatException nfe) {
            result = (float) Integer.parseInt(s);
        }

        if (result != null && result < 0) {
            result = 0f;
        }

        return result;
    }

    public static boolean getc1Block(String s){
        boolean result = false;
        if(s == null || StringUtils.isBlank(s)){
            result = false;
        }
        else  {
            int res = Integer.parseInt(s);
            if(res == 1){
                result = true;
            }
        }
        return  result;
    }

    public static String getBlockCheck(boolean blockCheck){
        return  blockCheck ? "1" : "0";
    }

    /**
     * Привести дату к строке вида yyyyMMddHHmmss
     */
    private static String str(Timestamp date) {
        return sdf.format(date);
    }

    /**
     * Привести дату к строке вида yyyyMMddHHmmss
     */
    private static String str(Date date) {
        return sdf.format(date);
    }

    /**
     * Привести строку вида yyyyMMddHHmmss к дате
     */
    public static Date date(String str) throws java.text.ParseException {
        return new Date(sdf.parse(str).getTime());
    }

    /**
     * Привести строку вида yyyyMMddHHmmss к дате
     */
    public static Timestamp timestamp(String str) throws java.text.ParseException {
        return new Timestamp(sdf.parse(str).getTime());
    }


    private static void proceedOutOrderPrint(DataExchange dataExchange, Properties props, BooleanRef proceed) {
        if (!dataExchange.getTableName().equals(DocumentType.ORDER_PRINT)) {
            System.out.println("Эта ошибка");
            return;
        }

        /*
            Перед обработкой проверяем, что существует клиент и заказ, на который ссылается выгрузка
         */

        //  Проверяем, что такой заказ существует
        long orderId = dataExchange.getItemId();
        ru.niir.goodfil.db.Order order = gf.getOrderById(orderId);
        if (order == null) {
            logError("Missing order " + orderId + ": skipped");
            proceed.set(false);
            return;
        }

        //  Проверяем, что такой клиент существует
        long clientId = order.getClientId();
        ru.niir.goodfil.db.Client client = gf.getClientById(clientId);
        if (client == null) {
            logError("Order #" + order.getId() + " was obtained with missing client (" + clientId + ")");
            return;
        }

        List<ru.niir.goodfil.db.OrderItem> orderItems = gf.getOrderItemsByOrderId(orderId);
        //  Загрузка соответствующих товаров для сортировки по коду
        for (ru.niir.goodfil.db.OrderItem orderItem : orderItems) {
            ru.niir.goodfil.db.Good g = gf.getGoodById(orderItem.getGoodId());
            orderItem.setGood(g);
        }

        //  Сортировка по коду товара
        Collections.sort(orderItems, new Comparator<ru.niir.goodfil.db.OrderItem>() {
            public int compare(ru.niir.goodfil.db.OrderItem orderItem1, ru.niir.goodfil.db.OrderItem orderItem2) {
                return orderItem1.getGood().getCode().compareTo(orderItem2.getGood().getCode());
            }
        });

        String comment = "???";
        try {
            ExportStringFormatter formatter = new ExportStringFormatter(order, orderItems);
            comment = formatter.formatExportString();

//            float weight = 0;
//            for (ru.niir.goodfil.db.OrderItem oi : orderItems) {
//                weight += (oi.getGood().getWeight() * oi.getCount());
//            }
//
//            float volume = 0;
//            for (ru.niir.goodfil.db.OrderItem oi : orderItems) {
//                volume += (oi.getGood().getVolume() * oi.getCount());
//            }
//
//            BigDecimal bdWeight = new BigDecimal(String.valueOf(weight)).setScale(1, RoundingMode.HALF_UP);
//            BigDecimal bdVolume = new BigDecimal(String.valueOf(volume)).setScale(1, RoundingMode.HALF_UP);
//            comment = order.getDeliveryInfoExt().formatExportString(order.getDeliveryDate(), bdWeight, bdVolume);
        } catch (Exception e) {
            comment = e.toString();
        }

        //  К этому моменту мы знаем, что с заказом все в порядке. Заполняем Properties
        if (props != null) {
            props.clear();

            SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy HH:mm");
            String orderNum = String.valueOf(order.getId());
            String clientName = client.getCompanyName();
            String orderSum = String.valueOf(order.getSum());
            String orderCreationDate = sdf.format(order.getCreationDate());
            String dataExchangeId = String.valueOf(dataExchange.getId());
            String id1C = String.valueOf(order.getC1Num());
            String blockCheck = getBlockCheck(client.isBlockCheck());
            //   String priceColumn = "Колонка 1";

            props.setProperty("dataExchangeId", dataExchangeId);
            props.setProperty("managerId", String.valueOf(order.getManagerId()));
            props.setProperty("orderNum", orderNum);
            props.setProperty("clientName", clientName);
            props.setProperty("orderSum", orderSum);
            props.setProperty("orderCreationDate", orderCreationDate);
            props.setProperty("id1C", id1C);
            props.setProperty("blockCheck", blockCheck);
            //      props.setProperty("priceColumn", priceColumn);
        }

        Document document = Document.create(DocumentType.ORDER_PRINT);
        Order o = new Order(order.getId(),
                order.getC1Num(),
                client.getC1ClientNum(),
                String.valueOf(client.getId()),
                str(order.getCreationDate()),
                comment,
                String.valueOf(order.getFirm()),
                gf.getClientGroupById(gf.getClientById(clientId).getClientgroupIdByBrandId(1)).getName(), getBlockCheck(client.isBlockCheck()));

        //  Если заказ неудаленный, добавляем его содержимое. Если удаленный - передаем пустую шапку.
        if (!order.isDeleted()) {


            for (ru.niir.goodfil.db.OrderItem orderItem : orderItems) {
                ru.niir.goodfil.db.Good good = gf.getGoodById(orderItem.getGoodId());
                o.getItems().add(new OrderItem(good.getC1code(), orderItem.getCount(), orderItem.getItemPrice()));
            }
        }

        document.getOrders().add(o);

        if (writeDocument(document)) {
            gf.updateDataExchangeState(dataExchange.getId(), ExchangeState.SENT);
            proceed.set(true);
        }

        //  Надо не забыть удалить заказ вместе с закрытием выгрузки
    }

    private static void sendCalculationToManager(DataExchange dataExchange, Document document) throws MessagingException {
        ru.niir.goodfil.db.Order order = gf.getOrderById(dataExchange.getItemId());

        for (Order o : document.getOrders()) {
            try {
                if (o.getItems().size() == 0) {   //  Заказ принят в 1С

                    order.setC1Num(o.getId1C());
                    try {
                        gf.updateOrder(order);
                    } catch (ValidationException ve) {
                        logFatal("Cannot update order " + o.getIdIS() + ": " + ve);
                    }
                }
            }catch (Exception e){
                logFatal("Cannot change order status: " + e);
            }
        }
        SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yy");
        String fileName = order.getId() + "_" + sdf.format(dataExchange.getCreationDate())+".xls";
        String calculationFile = directory + File.separator + fileName;
        long managerId = order.getManagerId();
        User manager = gf.getUserById(managerId);
        _assertNotNull(manager);

        List<Replacement> replacements = gf.getActiveReplacementsByManagerId(managerId);
        _assertNotNull(replacements);
        _assert(replacements.size() == 0 || replacements.size() == 1);

        if (replacements.size() == 1) {
            Replacement replacement = replacements.get(0);
            logInfo("Manager " + replacement.getManagerId() + " replaced by " + replacement.getAssistantId());
            manager = gf.getUserById(replacement.getAssistantId());
            _assertNotNull(manager);
        }
        String companyName = gf.getClientById(order.getClientId()).getCompanyName();
        logger.debug("Sending report");
        gf.createIfNotExists(".smtp.host", "192.168.0.2", "Адрес почтового сервера в сети");
        gf.createIfNotExists(".smtp.port", "587", "Порт для доступа к почтовому серверу");
        gf.createIfNotExists(".smtp.username", "zakaz", "Имя пользователя для доступа к почтовому серверу");
        gf.createIfNotExists(".smtp.password", "50065", "Пароль для доступа к почтовому серверу");

        String host = gf.get(".smtp.host");
        String port = gf.get(".smtp.port");
        String username = gf.get(".smtp.username");
        String password = gf.get(".smtp.password");
        String caption = "Счет на заказ " + order.getId();
        String body = "Уважаемый(-ая), " + manager.getFio() + "!<br />Настоящим письмом Вам высылается счет на заказ номер " + order.getId() + ", клиента " + companyName +
                ". Это письмо было сгенерировано автоматически, отвечать на него не надо. <br /> Если Вы считаете, что данное письмо отправлено без " +
                "Вашей санкции, пожалуйста, сообщите нам по адресу info@goodfil.com. <br />" + "С Уважением,<br />администрация Goodwill.";

        Messager.sendEmailWithAttachment(host, port, username, password, manager.getEmail(), caption, body, calculationFile, fileName);
        Path path = FileSystems.getDefault().getPath(directory, fileName);
        try {
            Files.deleteIfExists(path);
        } catch (IOException e) {
            logError(e.getMessage());
        }
    }

    public static void proceedOstatki(DataExchange dataExchange, File f, BooleanRef proceed){
/*            for (File f : dir.listFiles()) {
                if (!f.getName().endsWith("Ostatki.xml")) {
                    continue;
                }*/
        gf.updateDataExchangeState(dataExchange.getId(), ExchangeState.SENT);
        try {
            FileInputStream fis = new FileInputStream(f);
            InputStreamReader in = new InputStreamReader(fis, "windows-1251");
            Document document = null;
            try {
                document = (Document) getXStream().fromXML(in);
            } catch (Exception e) {
            }

            if (document == null) {
                //  EXPERIMENTAL: Может приходить битый файл с остатками, к этому нужно спокойно относиться
                logError("Cannot parse Ostatki.xml from 1C");
                //continue;
                return;
//                        throw new RuntimeException("Cannot parse file from 1C ");
            }

            in.close();
            fis.close();

            if ((document.getRests() == null || document.getRests().size() == 0) &&
                    (document.getGoods() == null || document.getGoods().size() == 0) &&
                    (document.getClients() == null || document.getClients().size() == 0) &&
                    (document.getOrders() == null || document.getOrders().size() == 0) &&
                    document.getResponse() == null) {
                //continue;
                return;
            }
            proceedInputRests(document);        //  Остатки
            proceedInputGoods(document);        //  Товары
            proceedInputClients(document);      //  Долги
            proceedInputOrders(document);       //  Реализации
            proceedInputOrderBuild(document);

            SimpleDateFormat sdf = new SimpleDateFormat("dd.MM.yyyy hh:mm:ss");
            java.util.Date current = Calendar.getInstance().getTime();
            gf.createIfNotExists(".1c.rests.last", sdf.format(current), "Дата последней загрузки остатков");
            gf.set(".1c.rests.last", sdf.format(current));

            //  Перемещаем в папку proceed файл Ostatki.xml
            moveToProceed(f);
            Calendar endTime = Calendar.getInstance();
            proceed.set(true);
            System.out.println(endTime.getTime() + " Остатки загружены из 1С. Склад может подтверждать заявки");
        } catch (IOException ioe) {   //  Если не можем прочесть - НЕ выход (EXPERIMENTAL)
            ioe.printStackTrace();
            logError("Cannot read file: " + f.getName() + ". Exception: " + ioe);
        }
        //}

    }

    /**
     * Задача на периодическое выполнение.
     * @param context
     * @throws JobExecutionException
     */
    @Override
    public void execute(JobExecutionContext context) throws JobExecutionException {
//        Calendar startTime = Calendar.getInstance();
//        System.out.println(startTime.getTime() + " Началась выгрузка остатков. Складу запрещено подтверждать заявки.");
/*        try {
            Thread.sleep(300);
            System.out.println("Задержка");
        } catch (InterruptedException e) {
            e.printStackTrace();
        }*/
        DataExchange dataExchange = new DataExchange();
        dataExchange.setTableName("Rests");
        dataExchange.setItemId(0);
        try {
            gf.addDataExchange(dataExchange);
        } catch (ValidationException e) {
            e.printStackTrace();
        }
/*        File dir = new File(directory);
        boolean isOstatkiEsist = false;
        while (!isOstatkiEsist){
            for (File f : dir.listFiles()) {
                if (!f.getName().endsWith("Ostatki.xml")) {
                    continue;
                }
                System.out.println("Файл есть");
           //    proceedOstatki(f);
                isOstatkiEsist = true;
            }
        }*/
//        GoodsFilter filter = new GoodsFilter();
//        List<ru.niir.goodfil.db.Good> goods = gf.getGoods(filter);
//        Calendar endTime = Calendar.getInstance();
//        for(ru.niir.goodfil.db.Good good : goods){
//            System.out.println(good.getCode());
//        }
//        System.out.println(endTime.getTime() + " Остатки загружены из 1С. Склад может подтверждать заявки");
    }

    public static class ClientIsBlockedException extends Exception {
        private final Long managerId;

        private final Long dataExchangeId;

        private final Long orderId;

        public ClientIsBlockedException(Long managerId, Long dataExchangeId, Long orderId) {
            super("Client is blocked. managerId=" + String.valueOf(managerId) + ",dataExchangeId=" + String.valueOf(dataExchangeId) + ",orderId=" + String.valueOf(orderId));
            this.managerId = managerId;
            this.dataExchangeId = dataExchangeId;
            this.orderId = orderId;
        }

        public Long getManagerId() {
            return managerId;
        }

        public Long getDataExchangeId() {
            return dataExchangeId;
        }

        public Long getOrderId() {
            return orderId;
        }
    }
}
